import re
import sqlite3
from datetime import datetime
from qqwry import QQwry

def process_log_file(log_file_path, ui):
    """
    处理日志文件，将IP、字符串、点、时间戳和原始日志插入数据库。
    
    参数:
        log_file_path (str): 日志文件的路径
        ui (Ui_MainWindow): 主窗口的UI对象，用于更新进度条和标签
    """
    # 设置进度条和提示
    ui.label_2.setText("设置数据库")
    ui.progressBar.setValue(2)
    # 创建或连接SQLite数据库
    conn = sqlite3.connect('nginx_logs.db')
    cursor = conn.cursor()
    
    # 先删除旧表（如果存在），然后重新创建包含timestamp和原始日志列的表
    cursor.execute('DROP TABLE IF EXISTS nginx_logs')
    cursor.execute('''
    CREATE TABLE nginx_logs (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        ip TEXT,
        string TEXT,
        point INTEGER,
        timestamp INTEGER,
        original_log TEXT,
        address TEXT,
        lable TEXT
    )
    ''')
    
    # 创建system表
    cursor.execute('''
    CREATE TABLE IF NOT EXISTS system (
        id INTEGER PRIMARY KEY,
        total_count INTEGER
    )
    ''')
    
    # 清空现有表数据
    cursor.execute('DELETE FROM nginx_logs')
    cursor.execute('DELETE FROM system')
    # 设置进度条和提示
    ui.label_2.setText("格式化数据")
    ui.progressBar.setValue(3)
    # 正则表达式匹配IP地址
    ip_pattern = r'^(\S+)'
    # 正则表达式匹配第一个双引号中的内容
    quotes_pattern = r'"([^"]*)"'
    # 正则表达式匹配时间信息
    time_pattern = r'\[(.*?)\]'
    
    # 计数器
    total_lines = 0
    
    try:
        with open(log_file_path, 'r', encoding='utf-8', errors='ignore') as f:
            # 获取总行数
            counts = sum(1 for _ in f)
            
            f.seek(0)  # 重置文件指针到开头
            qqwry = QQwry()
            qqwry.load_file('./qqwry.dat')
            for line_num, line in enumerate(f, 1):
                total_lines += 1
                
                # 提取IP地址
                ip_match = re.match(ip_pattern, line)
                if ip_match:
                    ip = ip_match.group(1)
                    
                    # 提取时间信息
                    time_match = re.search(time_pattern, line)
                    timestamp = 0
                    if time_match:
                        time_str = time_match.group(1)
                        try:
                            # 解析nginx日志时间格式：18/Mar/2020:16:04:15 +0900
                            dt = datetime.strptime(time_str, '%d/%b/%Y:%H:%M:%S %z')
                            # 转换为Unix时间戳
                            timestamp = int(dt.timestamp())
                        except Exception as e:
                            # 如果时间解析失败，保持为0
                            print(f"解析时间失败: {time_str}, 错误: {e}")
                            timestamp = 0
                    try:
                        clientinfo = qqwry.lookup(ip)
                        clientaddress = clientinfo[0] + " " + clientinfo[1]
                    except Exception as e:
                        clientaddress = "未知"
                    # 提取第一个双引号内的内容
                    quoted_match = re.search(quotes_pattern, line)
                    
                    # 如果找到匹配，获取第一个双引号内容，否则使用空字符串
                    first_quoted_content = quoted_match.group(1) if quoted_match else ''
                    
                    # 插入数据到nginx_logs表，添加timestamp和原始日志字段
                    cursor.execute(
                        'INSERT INTO nginx_logs (ip, string, point, timestamp, original_log, address) VALUES (?, ?, ?, ?, ?, ?)',
                        (ip, first_quoted_content, 0, timestamp, line.strip(), clientaddress)
                    )
                # 获取百分比
                percent = int(line_num / counts * 100)
                ui.label_2.setText(f"格式化数据 {percent}% - {line_num} / {counts}")
                ui.progressBar.setValue(percent)
                # 每1000行提交一次，避免内存占用过大
                if total_lines % 1000 == 0:
                    conn.commit()
        
        # 最终提交剩余数据
        conn.commit()
        
        # 保存总条数到system表
        cursor.execute('INSERT INTO system (id, total_count) VALUES (1, ?)', (total_lines,))
        conn.commit()
        
    except Exception as e:
        ui.label_2.setText(f"处理日志时出错")
        print(f'处理日志时出错: {e}')
    finally:
        conn.close()